<?php 
/**
 * This file is part of DomAr.
 * 
 * DomAr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * DomAr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with DomAr.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @link http://inditel.ee/
 * @copyright 2007-2009 Inditel Meedia OÜ
 * @author Oliver Leisalu <oliver@inditel.ee>
 */


/**
* @package DomAr
*/
class DomArSession {

	protected $newList = array();
	
	protected $newObjects = array();
	
	protected $list = array();
	
	protected $savedList = array();
	
	protected $changedList = array();
	
	//protected $relations = array();
	
	public function __construct( DomArObject $object ) {
		$this->add( $object );
	}
	
	public function add( DomArObject $object ) {
		$this->list[spl_object_hash($object)] = $object;
		if( $object->id == 0 )
			$this->newList[spl_object_hash($object)] = $object;
		else
			$this->savedList[spl_object_hash($object)] = $object;
	}
	
	/*public function addRelation( DomArObject $parent, DomArObject $needs ) {
		$this->relations[spl_object_hash($parent)][spl_object_hash($needs)] = 1;
	}*/
	
	
	// -----------------------------------------
	// SAVE 
	// -----------------------------------------
	

	public function save() {

		// ------------------
		// before listeners
		// to $this->list items can be added in before listeners so we use dynamic walking on it.
		do {
			$object = current($this->list);
			if( $object->getId() == 0 ) {
				$object->_beforeInsert( $this );
				$this->newObjects[] = $object;
			} else
				$object->_beforeUpdate( $this );
				
			$this->changedList[spl_object_hash($object)] = array();

		} while( next($this->list) !== false );
		// ------------------
		
		
		
		
		// ------------------
		// Validating
		foreach( $this->newObjects as $object )
			$object->validateUnchangedProperties();
		
		$validated = true;
		$validationInfo = array();
		foreach( $this->list as $object ) {
			if( $object->validated() === false ) {
				$validated = false;
				$validationInfo = array_merge( $validationInfo, $object->getValidationInfo() );
			}
		}
		
		if( $validated === false ) {
			// this generates DomArValidation report which makes static last report and can be accessed by DomArObject::getValidationReport();
			new DomArValidationReport( $validationInfo );
			return;
		}
		//throw new RuntimeException('Objects in session are not validated. Failed validation error messages: <br><ul><li> '.implode('</li><li>', $this->getFailedValidationMessages() ).'</li></ul>');
		// ------------------

		// ------------------
		// make queries
		DomSql::query('START TRANSACTION');	
		try {
			foreach( $this->getOrderedList() as $object ) {

				$changed = $object->getChanged();
				$this->changedList[spl_object_hash($object)] = array_merge( $this->changedList[spl_object_hash($object)], $changed );
				$object->setChanged( false );
				
				// insert
				if( $object->getId() == 0 ) {
					$set = new DomArInsertValueSet();
					$object->_insert( $set );
					DomSql::query( 'INSERT INTO '.$object->getDbTable().' (className'.$set->getColumns().') VALUES (\''.get_class($object).'\''.$set->getValues().')' );	
					$object->setId( (int)DomSql::lastInsertId() );
				// update
				} else {
					$set = new DomArUpdateValueSet();
					$object->_update( $changed, $set );
					if( $set->isEmpty() === false )
						DomSql::query( 'UPDATE '.$object->getDbTable().' SET '.$set->getUpdates().' WHERE id = '.$object->getId().' LIMIT 1' );		
				}
				
			}
		} catch( Exception $e ) {
			DomSql::query('ROLLBACK');
			throw $e;
		}
		DomSql::query('COMMIT');
		// ------------------


		// ------------------
		// after listeners
		foreach( $this->list as $object ) {
			if( isset($this->newList[spl_object_hash($object)]) === true )
				$object->_afterInsert();
			else
				$object->_afterUpdate( $this->changedList[spl_object_hash($object)] );
		}
		// ------------------
		
		
		return true;
	}

	
	public function getOrderedList() {
		
		// do some smart ordering algorithm
		
		
		// currently this is THE SMART algorithm! NOT very smarty through
		return array_merge( array_values($this->newList), array_values($this->newList), array_values($this->savedList) );
	}

}
?>